# -*-coding: utf-8 -*-
"""
作者：TianyiFan
日期：2023-年10-月31日
用途：存放各类自模型的类
"""
import copy
import time

from gurobipy import *
from docplex.mp.model import Model as Cplex_model
from docplex.mp.conflict_refiner import ConflictRefiner


import common_fuc
import para as params
import numpy as np

class submodel_gurobi(object):
    '''给定堆场分配结果，求解装卸量分配的submodel'''
    def __init__(self, ganma_ik):
        '''
        在确定不同船堆场分配的基础上，求解对应的装卸资源分配问题
        :param ganma_ik:
        :return:
        '''
        self.maxbound = 9999
        self.minbound = -9999
        self.model = Model("submodel-1")
        self.model.setParam("OutputFlag", params.outflag_PP)
        self.model.setParam("MIPFocus", 3)
        self.obj =  params.max_bound
        self.beta_lik, self.beta_uik = {}, {}
        self.alpha_lih,self.alpha_uih = {},{}
        self.cost_plan_i = {}
        self.deta_u_i = {}
        self.deta_l_i = {}
        self.abs_ui1 = {}
        self.abs_li1 = {}
        self.sum_li1 = {}
        self.sum_ui1 = {}
        self.gamma_ik = ganma_ik
        # endregion

    def operate_model(self):
        for i in range(params.V + 2):
            self.cost_plan_i = self.model.addVar(0, self.maxbound, vtype=GRB.INTEGER, name="cost_plan_{}".format(i))
            for h in range(params.H):
                name1 = "alpha_uij_{0:>2}_{1}_".format(i, h)
                name2 = "alpha_lij_{0:>2}_{1}_".format(i, h)
                self.alpha_uih[i, h] = self.model.addVar(0, params.c_ui[i], vtype=GRB.INTEGER, name=name1)
                self.alpha_lih[i, h] = self.model.addVar(0, params.c_li[i], vtype=GRB.INTEGER, name=name2)
        for i in range(params.V + 2):
            for k in range(params.K1):
                name3 = "beta_l{0}_{1}".format(i, k)
                name4 = "beta_u{0}_{1}".format(i, k)
                self.beta_lik[i, k] = self.model.addVar(0, params.z, vtype=GRB.INTEGER, name=name3)
                self.beta_uik[i, k] = self.model.addVar(0, params.z, vtype=GRB.INTEGER, name=name4)
        for i in range(params.V + 2):
            name6 = "deta_u_{0}".format(i)
            name7 = "deta_l_{0}".format(i)
            name8 = "abs_u_{0}".format(i)
            name9 = "abs_l_{0}".format(i)
            name10 = "sum_u_{0}".format(i)
            name11 = "sum_i_{0}".format(i)
            self.deta_u_i[i] = self.model.addVar(0, self.maxbound, vtype=GRB.INTEGER, name=name6)
            self.deta_l_i[i] = self.model.addVar(0, self.maxbound, vtype=GRB.INTEGER, name=name7)
            self.abs_ui1[i] = self.model.addVar(0, self.maxbound, vtype=GRB.INTEGER, name=name8)
            self.abs_li1[i] = self.model.addVar(0, self.maxbound, vtype=GRB.INTEGER, name=name9)
            self.sum_ui1[i] = self.model.addVar(self.minbound, self.maxbound, vtype=GRB.INTEGER, name=name10)
            self.sum_li1[i] = self.model.addVar(self.minbound, self.maxbound, vtype=GRB.INTEGER, name=name11)

            # region 添加约束
        for i in range(1, params.V + 1):
            for h in range(params.H):
                self.model.addConstr(self.deta_l_i[i] >= self.alpha_lih[i, h], name="linearing cons1_{0}_{1}".format(i, h))
                self.model.addConstr(self.deta_u_i[i] >= self.alpha_uih[i, h], name="linearing cons2_{0}_{1}".format(i, h))
                # 最小化目标函数时，绝对值的线性化=恒大于两者最小

        for i in range(1, params.V + 1):
            expr3 = quicksum(self.beta_lik[i, k] for k in range(params.K0))
            expr4 = quicksum(self.beta_uik[i, k] for k in range(params.K0))
            self.model.addConstr(self.sum_li1[i] == self.alpha_lih[i, 0] - expr3, name="Constrain_sum_l_{0}".format(i))
            self.model.addConstr(self.sum_ui1[i] == self.alpha_uih[i, 0] - expr4, name="Constrain_sum_u_{0}".format(i))

        for i in range(1, params.V + 1):
            self.model.addGenConstrAbs(self.abs_li1[i], self.sum_li1[i], name="abs_constrain_l_{0}".format(i))
            self.model.addGenConstrAbs(self.abs_ui1[i], self.sum_ui1[i], name="abs_constrain_u_{0}".format(i))
            # 约束2/4：每艘船的unloading量守恒、loading量守恒
        if 1 == 1:
            for i in range(1, params.V + 1):
                expr1 = LinExpr(0)
                expr2 = LinExpr(0)
                for h in range(params.H):
                    expr1.add(self.alpha_uih[i, h])
                    expr2.add(self.alpha_lih[i, h])
                self.model.addConstr(expr1 == params.c_ui[i], name="Constrain2_u_{0}".format(i))
                self.model.addConstr(expr2 == params.c_li[i], name="Constrain4_l_{0}".format(i))
            # 约束 3/5：每艘船unloading/loading到堆场的数量守恒
        if 1 == 1:
            for i in range(1, params.V + 1):
                expr3 = LinExpr(0)
                expr4 = LinExpr(0)
                for k in range(params.K1):
                    expr3.add(self.beta_uik[i, k])
                    expr4.add(self.beta_lik[i, k])
                self.model.addConstr(expr3 == params.c_ui[i], name="Constrain_3_u_{0}".format(i))
                self.model.addConstr(expr4 == params.c_li[i], name="Constrain_5_l_{0}".format(i))

            # 约束6：unloading 和 loading 在每一层的守恒
        if 1 == 1:
            for i in range(1, params.V + 1):
                for k in range(params.K1):
                    self.model.addConstr(self.beta_lik[i, k] + self.beta_uik[i, k] <= params.z, name="Constrain6_{0}_{1}".format(i, k))

            # 约束7-8：每个堆场的loading、unloading 量
        for i in range(1, params.V + 1):
            for k in range(params.K1):
                self.model.addConstr(self.beta_lik[i, k] <= params.z * self.gamma_ik[i, k], name="Constrain7_l_{0}_{1}".format(i, k))
                self.model.addConstr(self.beta_uik[i, k] <= params.z * self.gamma_ik[i, k], name="Constrain8_u_{0}_{1}".format(i, k))

            # 约束13：每个time step，异层转运的数量不能超过一个阈值
        if 1 == 1:
            for t in range(params.T):
                expr = LinExpr(0)
                for i in range(1, params.V + 1):
                    if params.l_it[i][t] == 1:
                        expr.addTerms(1 / params.handle_i[i], self.abs_ui1[i])
                        expr.addTerms(1 / params.handle_i[i], self.abs_li1[i])
                self.model.addConstr(expr <= params.C, name="Constrain13_{0}".format(t))

            # region 定义目标函数
            obj = LinExpr(0)
            for i in range(1, params.V + 1):
                expr1 = LinExpr(0)
                expr1.addTerms(params.time_p, self.deta_l_i[i])
                expr1.addTerms(params.time_p, self.deta_u_i[i])
                expr1.addTerms(params.time_u, self.abs_li1[i])
                expr1.addTerms(params.time_u, self.abs_ui1[i])
                expr2 = LinExpr(0)
                for k in range(params.K1):
                    expr2.addTerms(params.t_uki[k][i], self.beta_uik[i, k])
                    expr2.addTerms(params.t_lki[k][i], self.beta_lik[i, k])
                obj.add(expr1)
                obj.add(expr2)
            self.model.setObjective(obj, GRB.MINIMIZE)
            # endregion
        self.model.update()

        print("开始求解submodel")
        self.model.optimize()
        print("submodel模型的求解状态：", self.model.getAttr(GRB.attr.Status))
        print('----------optimal status-----------')
        if self.model.getAttr(GRB.attr.Status) == 2:
            self.obj = self.model.ObjVal
            print("IP_submodel模型的最优解 = {1:.2f} s  转化为小时={0:.2f} hours".format(self.model.ObjVal / 3600, self.model.ObjVal))
            cost_i = [0 for _ in range(params.V + 1)]
            for i in range(1, params.V + 1):
                cost1 = params.time_p * (max(self.alpha_uih[i, 0].x, self.alpha_uih[i, 1].x) + max(self.alpha_lih[i, 0].x, self.alpha_lih[i, 1].x))
                cost2222 = params.time_u * (self.abs_ui1[i].x + self.abs_li1[i].x)  # 直接用等价的绝对值进行累加计算
                # unloading_value = 0
                # loading_Value = 0
                # for k in range(params.K0):
                #     unloading_value += self.beta_uik[i, k].x
                #     loading_Value += self.beta_lik[i, k].x
                # # print("abs_ui1 ={}   公式计算的abs_ui1={}".format(abs_ui1[i].x,abs(alpha_uih[i, 0].x - unloading_value)))
                # cost2 = params.time_u * (abs(params.alpha_lih[i, 0].x - loading_Value) + abs(params.alpha_uih[i, 0].x - unloading_value))
                # print("abs直接计算的结果={}   由原来的公式计算的结果={}".format(cost2222,cost2))
                cost3 = 0
                for k in range(params.K1):
                    cost3 += params.t_lki[k, i] * self.beta_lik[i, k].x + params.t_uki[k, i] * self.beta_uik[i, k].x
                cost_i[i] = cost1 + cost2222 + cost3
                # print("vessel-{} 的总成本={}".format(i, cost_i[i]))
        elif self.model.getAttr(GRB.attr.Status) == 3:
            print("无解")
            print('Optimization was stopped with status =  %d' % self.model.getAttr(GRB.attr.Status))
            self.model.computeIIS()
            for c in self.model.getConstrs():
                if c.IISConstr:
                    print('%s' % c.constrName)
            raise StopIteration('sub-model was stopped with status =  %d' % self.model.getAttr(GRB.attr.Status))
        elif self.model.getAttr(GRB.attr.Status) == 5:
            print("无界解")

class submodel_cplex(object):
    def __init__(self):
        self.optimal_rd = solution_record()
        self.solving_time = 0
        self.obj = params.max_bound
        self.output_log = False
    def build_model(self,ganma_ik):
        time_start = time.time()
        maxbound = 999999
        minbound = -999999
        model = Cplex_model()

        # region 定义决策变量
        alpha_uih = {}
        alpha_lih = {}
        beta_lik = {}
        beta_uik = {}
        for i in range(params.V + 2):
            for h in range(params.H):
                name1 = "alpha_uij_{0:>2}_{1}_".format(i, h)
                name2 = "alpha_lij_{0:>2}_{1}_".format(i, h)
                alpha_uih[i, h] = model.integer_var(0, params.c_ui[i], name=name1)
                alpha_lih[i, h] = model.integer_var(0, params.c_li[i], name=name2)
        for i in range(params.V + 2):
            for k in range(params.K1):
                name3 = "beta_l{0}_{1}".format(i, k)
                name4 = "beta_u{0}_{1}".format(i, k)
                beta_lik[i, k] = model.integer_var(0, params.z, name=name3)
                beta_uik[i, k] = model.integer_var(0, params.z, name=name4)
        # 辅助决策变量
        deta_u_i = {}
        deta_l_i = {}
        abs_ui1 = {}
        abs_li1 = {}
        sum_li1 = {}
        sum_ui1 = {}
        for i in range(1, params.V + 1):
            name6 = "deta_u_{0}".format(i)
            name7 = "deta_l_{0}".format(i)
            name8 = "abs_u_{0}".format(i)
            name9 = "abs_l_{0}".format(i)
            name10 = "sum_u_{0}".format(i)
            name11 = "sum_i_{0}".format(i)
            deta_u_i[i] = model.integer_var(0, maxbound, name=name6)
            deta_l_i[i] = model.integer_var(0, maxbound, name=name7)
            abs_ui1[i] = model.integer_var(0, maxbound, name=name8)
            abs_li1[i] = model.integer_var(0, maxbound, name=name9)
            sum_ui1[i] = model.integer_var(minbound, maxbound, name=name10)
            sum_li1[i] = model.integer_var(minbound, maxbound, name=name11)
        # endregion

        # region 定义目标函数
        obj_expr = model.linear_expr()  # 创建一个空的线性表达式对象
        for i in range(1, params.V + 1):
            expr1 = model.linear_expr()  # 创建一个空的线性表达式对象
            expr1.add_term(deta_l_i[i], params.time_p)
            expr1.add_term(deta_u_i[i], params.time_p)
            expr1.add_term(abs_li1[i], params.time_u)
            expr1.add_term(abs_ui1[i], params.time_u)
            expr2 = model.linear_expr()  # 创建一个空的线性表达式对象
            for k in range(params.K1):
                expr2.add_term(beta_uik[i, k], params.t_uki[k][i])
                expr2.add_term(beta_lik[i, k], params.t_lki[k][i])
            obj_expr.add(expr1)
            obj_expr.add(expr2)
        model.minimize(obj_expr)
        # endregion

        # region 定义约束条件
        # 目标函数中的等价替换
        for i in range(1, params.V + 1):
            for h in range(params.H):
                model.add(deta_l_i[i] >= alpha_lih[i, h], name="linearing cons1_{0}_{1}".format(i, h))
                model.add(deta_u_i[i] >= alpha_uih[i, h], name="linearing cons2_{0}_{1}".format(i, h))
        for i in range(1, params.V + 1):
            expr3 = model.sum(beta_lik[i, k] for k in range(params.K0))
            expr4 = model.sum(beta_uik[i, k] for k in range(params.K0))
            model.add(sum_li1[i] == alpha_lih[i, 0] - expr3, name="Constrain_sum_l_{0}".format(i))
            model.add(sum_ui1[i] == alpha_uih[i, 0] - expr4, name="Constrain_sum_u_{0}".format(i))
        for i in range(1, params.V + 1):
            model.add(abs_li1[i] == model.abs(sum_li1[i]), name="abs_constrain_l_{0}".format(i))
            model.add(abs_ui1[i] == model.abs(sum_ui1[i]), name="abs_constrain_u_{0}".format(i))
        # 约束2/4：每艘船的unloading量守恒、loading量守恒
        if 1 == 1:
            for i in range(1, params.V + 1):
                expr1 = model.sum(alpha_uih[i, h] for h in range(params.H))
                expr2 = model.sum(alpha_lih[i, h] for h in range(params.H))
                model.add(expr1 == params.c_ui[i], name="Constrain2_u_{0}".format(i))
                model.add(expr2 == params.c_li[i], name="Constrain4_l_{0}".format(i))
        # 约束 3/5：每艘船unloading/loading到堆场的数量守恒
        if 1 == 1:
            for i in range(1, params.V + 1):
                expr3 = model.sum(beta_uik[i, k] for k in range(params.K1))
                expr4 = model.sum(beta_lik[i, k] for k in range(params.K1))
                model.add(expr3 == params.c_ui[i], name="Constrain2_u_{0}".format(i))
                model.add(expr4 == params.c_li[i], name="Constrain4_l_{0}".format(i))
        # 约束6：unloading 和 loading 在每一层的守恒
        if 1 == 1:
            for i in range(1, params.V + 1):
                for k in range(params.K1):
                    model.add(beta_lik[i, k] + beta_uik[i, k] <= params.z, name="Constrain6_{0}_{1}".format(i, k))

        # 约束7-8：每个堆场的loading、unloading 量
        for i in range(1, params.V + 1):
            for k in range(params.K1):
                model.add(beta_lik[i, k] <= params.z * ganma_ik[i, k], name="Constrain7_l_{0}_{1}".format(i, k))
                model.add(beta_uik[i, k] <= params.z * ganma_ik[i, k], name="Constrain8_u_{0}_{1}".format(i, k))

        if 1 == 1:
            for t in range(params.T):
                expr = model.linear_expr()
                for i in range(1, params.V + 1):
                    if params.l_it[i][t] == 1:
                        expr.add_term(abs_ui1[i], 1 / params.handle_i[i])
                        expr.add_term(abs_li1[i], 1 / params.handle_i[i])
                model.add(expr <= params.C, name="Constrain13_{0}".format(t))
        # endregion

        solution = model.solve(log_output=self.output_log)
        time_end = time.time()
        num_variables = model.number_of_variables
        num_constraints = model.number_of_constraints
        refiner = ConflictRefiner()  # 先实例化ConflictRefiner类
        res = refiner.refine_conflict(model)  # 将模型导入该类，调用方法
        res.display()
        print("docplex_sub_model 中决策变量个数={}  约束数量={}".format(num_variables, num_constraints))
        if solution is not None:
            model_obj = solution.get_objective_value()
            self.solving_time = round(time_end - time_start, 2)
            self.obj = solution.get_objective_value()
            # 更新记录最优解的类对象
            for i in range(1, params.V + 1):
                for h in range(params.H):
                    self.optimal_rd.alpha_lih[i, h] = solution.get_var_value(alpha_lih[i, h])
                    self.optimal_rd.alpha_uih[i, h] = solution.get_var_value(alpha_uih[i, h])
                    self.optimal_rd.abs_li1[i] = solution.get_var_value(abs_li1[i])
                    self.optimal_rd.abs_ui1[i] = solution.get_var_value(abs_ui1[i])
                for k in range(params.K1):
                    if ganma_ik[i, k] > 0.5:
                        self.optimal_rd.beta_lik[i, k] = solution.get_var_value(beta_lik[i, k])
                        self.optimal_rd.beta_uik[i, k] =  solution.get_var_value(beta_uik[i, k])
            self.optimal_rd.cal_cost_i()

            print("docplex 求解结果： obj = {0:.2f} s  转化为小时={1:.2f} h".format(model_obj,model_obj/3600))
            print("每艘船预留堆场的最优解情况-------------")
            cost_i = [0 for _ in range(params.V + 1)]
            for i in range(1, params.V + 1):
                cost1 = params.time_p * (max(solution.get_var_value(alpha_lih[i, 0]),solution.get_var_value(alpha_lih[i, 1])) +
                                         max(solution.get_var_value(alpha_uih[i, 0]),solution.get_var_value(alpha_uih[i, 0])))
                cost2222 = params.time_u * (solution.get_var_value(abs_ui1[i])+ solution.get_var_value(abs_li1[i]))
                cost3 = 0
                for k in range(params.K1):
                    cost3 += params.t_lki[k, i] *solution.get_var_value(beta_lik[i, k]) + params.t_uki[k, i] *solution.get_var_value(beta_uik[i, k])
                cost_i[i] = cost1 + cost2222 + cost3
        else:
            raise EOFError("docplex 无解!")

class solution_record:
    '''
    专门用于存放原模型结果的类
    '''
    def __init__(self):
        self.obj =  params.max_bound
        self.solving_time = 0
        self.gamma_ik = np.zeros([params.V + 2, params.K1], dtype=int)
        self.beta_lik = np.zeros([params.V + 2, params.K1], dtype=int)
        self.beta_uik = np.zeros([params.V + 2, params.K1], dtype=int)
        self.alpha_lih =  np.zeros([params.V + 2, params.H], dtype=int)
        self.alpha_uih =  np.zeros([params.V + 2, params.H], dtype=int)
        self.deta_u_i = np.zeros(params.V+2, dtype=float)
        self.deta_l_i = np.zeros(params.V+2, dtype=float)
        self.abs_ui1 = np.zeros(params.V+2, dtype=float)
        self.abs_li1 = np.zeros(params.V+2, dtype=float)
        self.cost_i = np.zeros(params.V+2, dtype=float)
    def cal_cost_i(self):
        '''根据给定的alpha，beta，abs，计算每艘船的成本'''
        for i in range(1, params.V + 1):
            self.deta_l_i[i] = max(self.alpha_lih[i])
            self.deta_u_i[i] = max(self.alpha_uih[i])
            cost1 = params.time_p * (self.deta_l_i[i] + self.deta_u_i[i])
            cost2 = params.time_u * (self.abs_li1[i] + self.abs_ui1[i])
            cost3 = 0
            for k in range(params.K1):
                cost3 += params.t_uki[k, i] * self.beta_uik[i, k] + params.t_lki[k, i] * self.beta_lik[i, k]
            self.cost_i[i] = cost1 + cost2 + cost3
            self.obj += self.cost_i[i]

class swo_model:
    def __init__(self,temp_sequence,swo_object):
        self.model = Model("SWO_gurobi_model")
        self.model.setParam("OutputFlag", params.outflag_SWO)
        self.model.Params.presolve = 1
        self.temp_sequence = temp_sequence  # temp_sequence 代表给定船的序列信息
        self.swo_record = swo_object        # swo_object为固定的解，self.swo_record 代表需要固定当前模型变量的值
        self.maxbound = 999999
        self.minbound = -999999
        self.beta_lik, self.beta_uik = {}, {}
        self.alpha_lih, self.alpha_uih = {}, {}
        self.gamma_ik = {}
        self.cost_plan_i = {}
        self.deta_u_i = {}
        self.deta_l_i = {}
        self.abs_ui1 = {}
        self.abs_li1 = {}
        self.sum_li1 = {}
        self.sum_ui1 = {}
        self.vessel_list = list(self.temp_sequence['vessel_idx'])
        print("vessel_list = {}".format(self.vessel_list))
        # region 初始化决策变量
        for i in range(params.V):
            vessel_idx = self.vessel_list[i]
            # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
            for h in range(params.H):
                name1 = "alpha_uih_{0:>2}_{1}_".format(i, h)
                name2 = "alpha_lih_{0:>2}_{1}_".format(i, h)
                self.alpha_uih[i, h] = self.model.addVar(0, params.c_ui[vessel_idx], vtype=GRB.INTEGER, name=name1)
                self.alpha_lih[i, h] = self.model.addVar(0, params.c_li[vessel_idx], vtype=GRB.INTEGER, name=name2)
        for i in range(params.V):
            for k in range(params.K1):
                name3 = "beta_l{0}_{1}".format(i, k)
                name4 = "beta_u{0}_{1}".format(i, k)
                name5 = "ganma_{0}_{1}".format(i, k)
                self.beta_lik[i, k] = self.model.addVar(0, params.z, vtype=GRB.INTEGER, name=name3)
                self.beta_uik[i, k] = self.model.addVar(0, params.z, vtype=GRB.INTEGER, name=name4)
                self.gamma_ik[i, k] = self.model.addVar(0, 1, vtype=GRB.BINARY, name=name5)
        for i in range(params.V):
            name6 = "deta_u_{0}".format(i)
            name7 = "deta_l_{0}".format(i)
            name8 = "abs_u_{0}".format(i)
            name9 = "abs_l_{0}".format(i)
            name10 = "sum_u_{0}".format(i)
            name11 = "sum_i_{0}".format(i)
            self.deta_u_i[i] = self.model.addVar(0, self.maxbound, vtype=GRB.INTEGER, name=name6)
            self.deta_l_i[i] = self.model.addVar(0, self.maxbound, vtype=GRB.INTEGER, name=name7)
            self.abs_ui1[i] = self.model.addVar(0, self.maxbound, vtype=GRB.INTEGER, name=name8)
            self.abs_li1[i] = self.model.addVar(0, self.maxbound, vtype=GRB.INTEGER, name=name9)
            self.sum_ui1[i] = self.model.addVar(self.minbound, self.maxbound, vtype=GRB.INTEGER, name=name10)
            self.sum_li1[i] = self.model.addVar(self.minbound, self.maxbound, vtype=GRB.INTEGER, name=name11)
        # endregion

    def operate_model(self,N):
        iter_id = N
        local_V = min(params.search_DS + N, params.V)  # 一共输入V艘船，就针对该V艘船的model进行求解，索引参数用取自vessel_idx
        # region 定义目标函数
        obj = LinExpr(0)
        for i in range(local_V):
            expr1 = LinExpr(0)
            expr1.addTerms(params.time_p, self.deta_l_i[i])
            expr1.addTerms(params.time_p, self.deta_u_i[i])
            expr1.addTerms(params.time_u, self.abs_li1[i])
            expr1.addTerms(params.time_u, self.abs_ui1[i])
            expr2 = LinExpr(0)
            vessel_idx = self.vessel_list[i]
            for k in range(params.K1):
                expr2.addTerms(params.t_uki[k][vessel_idx], self.beta_uik[i, k])
                expr2.addTerms(params.t_lki[k][vessel_idx], self.beta_lik[i, k])
            obj.add(expr1)
            obj.add(expr2)
        self.model.setObjective(obj, GRB.MINIMIZE)
        # endregion

        # 先固定前N艘船的决策结果---需要找到对应的vessel_idx，当iter_id=1是，不进行下面操作
        for iter_index in range(iter_id):
            n = iter_index  # 被固定的轮船的索引比迭代次数少2
            # vessel_idx = self.temp_sequence.iloc[n]['vessel_idx']
            vessel_idx = self.vessel_list[n]
            print("第 {} 次迭代，提前固定船-{} 的结果, n = {}".format(iter_id+1,vessel_idx,n))
            # print("self.abs_uil[n].name = {}".format(self.abs_ui1[n].varName))
            # print("self.swo_record.abs_ui1= {}".format( self.swo_record.abs_ui1[vessel_idx]))
            self.model.addConstr(self.abs_ui1[n] == self.swo_record.abs_ui1[vessel_idx], name="fixed_constrain6_{}".format(vessel_idx))
            self.model.addConstr(self.abs_li1[n] == self.swo_record.abs_li1[vessel_idx], name="fixed_constrain7_{}".format(vessel_idx))
            for k in range(params.K1):
                self.model.addConstr(self.gamma_ik[n, k] == self.swo_record.gamma_ik[vessel_idx, k], name="fixed_constrain1_{}_{}".format(vessel_idx,k))
                self.model.addConstr(self.beta_lik[n, k] == self.swo_record.beta_lik[vessel_idx, k], name="fixed_constrain2_{}_{}".format(vessel_idx,k))
                self.model.addConstr(self.beta_uik[n, k] == self.swo_record.beta_uik[vessel_idx, k], name="fixed_constrain3_{}_{}".format(vessel_idx,k))
            for h in range(params.H):
                self.model.addConstr(self.alpha_lih[n, h] == self.swo_record.alpha_lih[vessel_idx, h], name="fixed_constrain4_{}_{}".format(vessel_idx,h))
                self.model.addConstr(self.alpha_uih[n, h] == self.swo_record.alpha_uih[vessel_idx, h], name="fixed_constrain5_{}_{}".format(vessel_idx,h))
            # if vessel_idx in [4,19]:
            #     for k in range(params.K1):
            #         if self.swo_record.gamma_ik[vessel_idx,k]>0.5:
            #             print("v= {} k = {}  beta_lik = {}  beta_uik ={}".format(vessel_idx,k,self.swo_record.beta_lik[vessel_idx,k],self.swo_record.beta_uik[vessel_idx,k]))

        # region 添加约束
        # 最小化目标函数时，绝对值的线性化=恒大于两者最小
        for i in range(local_V):
            for h in range(params.H):
                self.model.addConstr(self.deta_l_i[i] >= self.alpha_lih[i, h], name="linearing cons1_{0}_{1}".format(i, h))
                self.model.addConstr(self.deta_u_i[i] >= self.alpha_uih[i, h], name="linearing cons2_{0}_{1}".format(i, h))
        for i in range(local_V):
            expr3 = quicksum(self.beta_lik[i, k] for k in range(params.K0))
            expr4 = quicksum(self.beta_uik[i, k] for k in range(params.K0))
            self.model.addConstr(self.sum_li1[i] == self.alpha_lih[i, 0] - expr3, name="Constrain_sum_l_{0}".format(i))
            self.model.addConstr(self.sum_ui1[i] == self.alpha_uih[i, 0] - expr4, name="Constrain_sum_u_{0}".format(i))
        for i in range(local_V):
            self.model.addGenConstrAbs(self.abs_li1[i], self.sum_li1[i], name="abs_constrain_l_{0}".format(i))
            self.model.addGenConstrAbs(self.abs_ui1[i], self.sum_ui1[i], name="abs_constrain_u_{0}".format(i))

        # 约束2/4：每艘船的unloading量守恒、loading量守恒
        if 1 == 1:
            for i in range(local_V):
                expr1 = LinExpr(0)
                expr2 = LinExpr(0)
                for h in range(params.H):
                    expr1.add(self.alpha_uih[i, h])
                    expr2.add(self.alpha_lih[i, h])
                vessel_idx = self.vessel_list[i]
                # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
                self.model.addConstr(expr1 == params.c_ui[vessel_idx], name="Constrain2_u_{0}".format(i))
                self.model.addConstr(expr2 == params.c_li[vessel_idx], name="Constrain4_l_{0}".format(i))
        # 约束 3/5：每艘船unloading/loading到堆场的数量守恒
        if 1 == 1:
            for i in range(local_V):
                expr3 = LinExpr(0)
                expr4 = LinExpr(0)
                for k in range(params.K1):
                    expr3.add(self.beta_uik[i, k])
                    expr4.add(self.beta_lik[i, k])
                vessel_idx = self.vessel_list[i]
                # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
                self.model.addConstr(expr3 == params.c_ui[vessel_idx], name="Constrain_3_u_{0}".format(i))
                self.model.addConstr(expr4 == params.c_li[vessel_idx], name="Constrain_5_l_{0}".format(i))

        # 约束6：unloading 和 loading 在每一层的守恒
        if 1 == 1:
            for i in range(local_V):
                for k in range(params.K1):
                    self.model.addConstr(self.beta_lik[i, k] + self.beta_uik[i, k] <= params.z, name="Constrain6_{0}_{1}".format(i, k))

        # 约束7-8：每个堆场的loading、unloading 量
        for i in range(local_V):
            for k in range(params.K1):
                self.model.addConstr(self.beta_lik[i, k] <= params.z * self.gamma_ik[i, k], name="Constrain7_l_{0}_{1}".format(i, k))
                self.model.addConstr(self.beta_uik[i, k] <= params.z * self.gamma_ik[i, k], name="Constrain8_u_{0}_{1}".format(i, k))

        # 约束9：每层的subblock需要小于对应的r_ih
        for i in range(local_V):
            expr1 = LinExpr(0)
            expr2 = LinExpr(0)
            for k in range(params.K0):
                expr1.add(self.gamma_ik[i, k])
            for k in range(params.K0, params.K1):
                expr2.add(self.gamma_ik[i, k])
            vessel_idx = self.vessel_list[i]
            # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
            self.model.addConstr(expr1 <= params.r_ih[vessel_idx][0], name="Constrain9_0_{0}".format(i))
            self.model.addConstr(expr2 <= params.r_ih[vessel_idx][1], name="Constrain9_1_{0}".format(i))

        # 约束10：每个subblock只能分配给一个堆场
        if 1 == 1:
            for k in range(params.K1):
                expr = LinExpr(0)
                for i in range(local_V):
                    expr.add(self.gamma_ik[i, k])
                self.model.addConstr(expr <= 1, name="Constrain10_{0}".format(k))

        # 约束11：每个time step，同一层的同一个block内，分配subblock数量不能超过3
        if 1 == 1:
            for t in range(params.T):
                if params.total_handle[t] >= 1:
                    for g in range(params.G):
                        expr = LinExpr(0)
                        for i in range(local_V):
                            vessel_idx = self.vessel_list[i]
                            # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
                            for k in params.block_set[g]:
                                expr.addTerms(params.l_it[vessel_idx][t], self.gamma_ik[i, k])
                        self.model.addConstr(expr <= 3, name="Constrain11_{0}_{1}".format(t, g))

        # 约束12：写法1--从每个subblock看，每个neighbor_set中，只能分配给一艘船
        if 1 == 1:
            for t in range(params.T):
                if params.total_handle[t] >= 1:
                    for n in range(params.K1):
                        for k in range(1, len(params.neighbor_set[n])):  # 不包括自己
                            midlist = [n]
                            midlist.append(params.neighbor_set[n][k])
                            expr = LinExpr(0)
                            index_neighbor = n
                            for i in range(local_V):
                                vessel_idx = self.vessel_list[i]
                                # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
                                for index in midlist:  # --形成一个pair 对 等价于 for k in neighbor_pair
                                    index_neighbor = index
                                    expr.addTerms(params.l_it[vessel_idx][t], self.gamma_ik[i, index])
                            self.model.addConstr(expr <= 1, name="Constrain12_{0}_({1}-{2})".format(t, n, index_neighbor))

        # 约束13：每个time step，异层转运的数量不能超过一个阈值
        if 1 == 1:
            for t in range(params.T):
                expr = LinExpr(0)
                for i in range(local_V):
                    vessel_idx = self.vessel_list[i]
                    # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
                    if params.l_it[vessel_idx][t] == 1:
                        expr.addTerms(1 / params.handle_i[vessel_idx], self.abs_ui1[i])
                        expr.addTerms(1 / params.handle_i[vessel_idx], self.abs_li1[i])
                self.model.addConstr(expr <= params.C, name="Constrain13_{0}".format(t))
        # endregion
        self.model.update()
        self.model.optimize()
        print("第 {} 次迭代SWO_model 中变量数量={}   约束数量={}".format(iter_id+1,self.model.NumVars, self.model.NumConstrs))
        # self.model.write('swo_model_{}.LP'.format(self.iter_id))

        # print("模型的求解状态：", self.model.getAttr(GRB.attr.Status))
        print('---------------optimal status----------------')
        if self.model.getAttr(GRB.attr.Status) == 2:
            print("模型的最优解 = {1:.2f} s  转化为小时={0:.2f} hours".format(self.model.ObjVal / 3600, self.model.ObjVal))
            cost_i = [0 for _ in range(local_V)]
            for i in range(local_V):
                vessel_idx = self.vessel_list[i]
                # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
                cost1 = params.time_p * (max(self.alpha_uih[i, 0].x, self.alpha_uih[i, 1].x) + max(self.alpha_lih[i, 0].x, self.alpha_lih[i, 1].x))
                cost2 = params.time_u * (self.abs_ui1[i].x + self.abs_li1[i].x)  # 直接用等价的绝对值进行累加计算
                cost3 = 0
                for k in range(params.K1):
                    cost3 += params.t_lki[k, vessel_idx] * self.beta_lik[i, k].x + params.t_uki[k, vessel_idx] * self.beta_uik[i, k].x
                cost_i[i] = cost1 + cost2 + cost3
                print("vessel-{:2} 的总成本={:8.2f} 预留堆场：".format(vessel_idx, cost_i[i]),end=" ")
                for k in range(params.K1):
                    if self.gamma_ik[i,k].x>0.5:
                        print(f"{k:3} ", end="")
                print()

        elif self.model.getAttr(GRB.attr.Status) == 3:
            print("无解")
            print('Optimization was stopped with status =  %d' % self.model.getAttr(GRB.attr.Status))
            self.model.computeIIS()
            for c in self.model.getConstrs():
                if c.IISConstr:
                    print('%s' % c.constrName)
            raise StopIteration('sub-model was stopped with status =  %d' % self.model.getAttr(GRB.attr.Status))
        elif self.model.getAttr(GRB.attr.Status) == 5:
            print("无界解")

class swo_cplex_model:
    def __init__(self,temp_sequence,swo_object):
        self.model = Cplex_model("SWO_cplex_model")
        self.output_flag = False
        self.temp_sequence = temp_sequence  # temp_sequence 代表给定船的序列信息
        self.swo_record = swo_object        # swo_object为固定的解，self.swo_record 代表需要固定当前模型变量的值,浅拷贝
        self.maxbound = 999999
        self.minbound = -999999
        self.beta_lik, self.beta_uik = {}, {}
        self.alpha_lih, self.alpha_uih = {}, {}
        self.gamma_ik = {}
        self.cost_plan_i = {}
        self.deta_u_i = {}
        self.deta_l_i = {}
        self.abs_ui1 = {}
        self.abs_li1 = {}
        self.sum_li1 = {}
        self.sum_ui1 = {}
        self.vessel_list = list(self.temp_sequence['vessel_idx'])
        self.conflict_list = list(self.temp_sequence['conflict_list'])
        # todo 将轮船索引映射对应的排序位置：
        self.vessel_to_seq = dict(zip(self.vessel_list,range(params.V)))
        print("confilct_list = {}".format(self.conflict_list))
        print("vessel_list = {}".format(self.vessel_list))
        # print("vessel_to_seq = {}".format(self.vessel_to_seq))
        # region 初始化决策变量
        for i in range(params.V):
            vessel_idx = self.vessel_list[i]
            # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
            for h in range(params.H):
                name1 = "alpha_uih_{0:>2}_{1}_".format(i, h)
                name2 = "alpha_lih_{0:>2}_{1}_".format(i, h)
                self.alpha_uih[i, h] = self.model.integer_var(0, params.c_ui[vessel_idx], name=name1)
                self.alpha_lih[i, h] = self.model.integer_var(0, params.c_li[vessel_idx], name=name2)
        for i in range(params.V):
            for k in range(params.K1):
                name3 = "beta_l{0}_{1}".format(i, k)
                name4 = "beta_u{0}_{1}".format(i, k)
                name5 = "ganma_{0}_{1}".format(i, k)
                self.beta_lik[i, k] = self.model.integer_var(0, params.z,name=name3)
                self.beta_uik[i, k] = self.model.integer_var(0, params.z,name=name4)
                self.gamma_ik[i, k] = self.model.binary_var(name=name5)
        for i in range(params.V):
            name6 = "deta_u_{0}".format(i)
            name7 = "deta_l_{0}".format(i)
            name8 = "abs_u_{0}".format(i)
            name9 = "abs_l_{0}".format(i)
            name10 = "sum_u_{0}".format(i)
            name11 = "sum_i_{0}".format(i)
            self.deta_u_i[i] = self.model.integer_var(0, self.maxbound, name=name6)
            self.deta_l_i[i] = self.model.integer_var(0, self.maxbound, name=name7)
            self.abs_ui1[i] = self.model.integer_var(0, self.maxbound, name=name8)
            self.abs_li1[i] = self.model.integer_var(0, self.maxbound, name=name9)
            self.sum_ui1[i] = self.model.integer_var(self.minbound, self.maxbound, name=name10)
            self.sum_li1[i] = self.model.integer_var(self.minbound, self.maxbound, name=name11)
        # endregion

    def operate_model(self,N):
        if N>0:
            self.model.set_time_limit(params.single_time_limit)  # 除了第一次之外单模型最多求20s
        time_start = time.time()
        iter_id = N  # N从0开始
        local_V = min(params.search_DS + N, params.V)  # 一共输入V艘船，就针对该V艘船的model进行求解，索引参数用取自vessel_idx
        # region 定义目标函数
        obj_expr = self.model.linear_expr()  # 创建一个空的线性表达式对象
        for i in range(local_V):
            expr1 = self.model.linear_expr()  # 创建一个空的线性表达式对象
            expr1.add((self.deta_l_i[i]+self.deta_u_i[i])*params.time_p+params.time_u*(self.abs_ui1[i]+self.abs_li1[i]))
            vessel_idx = self.vessel_list[i]
            expr2 = self.model.linear_expr()  # 创建一个空的线性表达式对象
            for k in range(params.K1):
                expr2.add(self.beta_uik[i, k]*params.t_uki[k][vessel_idx]+self.beta_lik[i, k]*params.t_lki[k][vessel_idx])
            obj_expr.add(expr1)
            obj_expr.add(expr2)
        self.model.minimize(obj_expr)
        # endregion

        # 先固定前N艘船的决策结果---需要找到对应的vessel_idx，当iter_id=0，不进行下面操作
        for iter_index in range(iter_id):
            n = iter_index  # 被固定的轮船的索引比迭代次数少2
            # vessel_idx = self.temp_sequence.iloc[n]['vessel_idx']
            vessel_idx = self.vessel_list[n]
            print("第 {} 次迭代，提前固定船-{} 的结果, n = {}".format(iter_id+1,vessel_idx,n))
            froze_subblock = []
            froze_neighbor_block = []
            # print("self.abs_uil[n].name = {}".format(self.abs_ui1[n].varName))
            # print("self.swo_record.abs_ui1= {}".format( self.swo_record.abs_ui1[vessel_idx]))
            self.model.add(self.abs_ui1[n] == self.swo_record.abs_ui1[vessel_idx], name="fixed_constrain6_{}".format(vessel_idx))
            self.model.add(self.abs_li1[n] == self.swo_record.abs_li1[vessel_idx], name="fixed_constrain7_{}".format(vessel_idx))
            for k in range(params.K1):
                if self.swo_record.gamma_ik[vessel_idx, k]>0.5:
                    froze_subblock.append(k)
                    for neighbor in params.neighbor_set[k][1:]:
                        froze_neighbor_block.append(neighbor)
                self.model.add(self.gamma_ik[n, k] == self.swo_record.gamma_ik[vessel_idx, k], name="fixed_constrain1_{}_{}".format(vessel_idx,k))
                self.model.add(self.beta_lik[n, k] == self.swo_record.beta_lik[vessel_idx, k], name="fixed_constrain2_{}_{}".format(vessel_idx,k))
                self.model.add(self.beta_uik[n, k] == self.swo_record.beta_uik[vessel_idx, k], name="fixed_constrain3_{}_{}".format(vessel_idx,k))
            for h in range(params.H):
                self.model.add(self.alpha_lih[n, h] == self.swo_record.alpha_lih[vessel_idx, h], name="fixed_constrain4_{}_{}".format(vessel_idx,h))
                self.model.add(self.alpha_uih[n, h] == self.swo_record.alpha_uih[vessel_idx, h], name="fixed_constrain5_{}_{}".format(vessel_idx,h))
            # todo 基于已经固定的堆场分配，封锁对应的subblock，让其sublock的决策提前为0
            froze_neighbor_block=set(froze_neighbor_block)
            # print("轮船-{} 的froze_subblock = {}   froze_neighbor = {}".format(vessel_idx,froze_subblock,froze_neighbor_block))
            # 固定约束1：已经预定的堆场，其他堆场的决策提前为0
            for froze_k in froze_subblock:
                for v_idx in range(n+1,local_V):
                   self.model.add( self.gamma_ik[v_idx,froze_k] == 0, name ="froze_constrain1_{}_{}".format(v_idx,froze_k))

            # 固定约束2：存在作业冲突的邻近堆场，决策变量可以提前固定
            if len(self.conflict_list[n])>0:
                for conflict_vessel in self.conflict_list[n]:
                    seq = self.vessel_to_seq[conflict_vessel]
                    for froze_k in froze_neighbor_block:
                        # print("提前将 vessel-{}  k={} 固定为0".format(conflict_vessel,froze_k))
                        self.model.add(self.gamma_ik[seq,froze_k] == 0,name="froze_constrain2_{}_{}".format(seq,froze_k))

        # region 添加约束
        # 最小化目标函数时，绝对值的线性化=恒大于两者最小
        for i in range(local_V):
            for h in range(params.H):
                self.model.add(self.deta_l_i[i] >= self.alpha_lih[i, h], name="linearing cons1_{0}_{1}".format(i, h))
                self.model.add(self.deta_u_i[i] >= self.alpha_uih[i, h], name="linearing cons2_{0}_{1}".format(i, h))
        for i in range(local_V):
            expr3 = self.model.sum(self.beta_lik[i, k] for k in range(params.K0))
            expr4 = self.model.sum(self.beta_uik[i, k] for k in range(params.K0))
            self.model.add(self.sum_li1[i] == self.alpha_lih[i, 0] - expr3, name="Constrain_sum_l_{0}".format(i))
            self.model.add(self.sum_ui1[i] == self.alpha_uih[i, 0] - expr4, name="Constrain_sum_u_{0}".format(i))
        for i in range(local_V):
            self.model.add(self.abs_li1[i] == self.model.abs(self.sum_li1[i]), name="abs_constrain_l_{0}".format(i))
            self.model.add(self.abs_ui1[i] == self.model.abs(self.sum_ui1[i]), name="abs_constrain_u_{0}".format(i))

        # 约束2/4：每艘船的unloading量守恒、loading量守恒
        if 1 == 1:
            for i in range(local_V):
                expr1 = self.model.sum(self.alpha_lih[i,h] for h in range(params.H))
                expr2 = self.model.sum(self.alpha_uih[i,h] for h in range(params.H))
                vessel_idx = self.vessel_list[i]
                # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
                self.model.add(expr1 == params.c_li[vessel_idx], name="Constrain4_l_{0}".format(i))
                self.model.add(expr2 == params.c_ui[vessel_idx], name="Constrain2_u_{0}".format(i))

        # 约束 3/5：每艘船unloading/loading到堆场的数量守恒
        if 1 == 1:
            for i in range(local_V):
                expr3 = self.model.sum(self.beta_lik[i,k] for k in range(params.K1))
                expr4 = self.model.sum(self.beta_uik[i, k] for k in range(params.K1))
                vessel_idx = self.vessel_list[i]
                # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
                self.model.add(expr3 == params.c_li[vessel_idx], name="Constrain_3_u_{0}".format(i))
                self.model.add(expr4 == params.c_ui[vessel_idx], name="Constrain_5_l_{0}".format(i))

        # 约束6：unloading 和 loading 在每一层的守恒
        if 1 == 1:
            for i in range(local_V):
                for k in range(params.K1):
                    self.model.add(self.beta_lik[i, k] + self.beta_uik[i, k] <= params.z*self.gamma_ik[i,k], name="Constrain6_{0}_{1}".format(i, k))

        # 约束9：每层的subblock需要小于对应的r_ih
        for i in range(local_V):
            expr1 = self.model.sum(self.gamma_ik[i, k] for k in range(params.K0))
            expr2 = self.model.sum(self.gamma_ik[i, k] for k in range(params.K0,params.K1))
            vessel_idx = self.vessel_list[i]
            # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
            self.model.add(expr1 <= params.r_ih[vessel_idx][0], name="Constrain9_0_{0}".format(i))
            self.model.add(expr2 <= params.r_ih[vessel_idx][1], name="Constrain9_1_{0}".format(i))

        # 约束10：每个subblock只能分配给一个堆场
        if 1 == 1:
            for k in range(params.K1):
                expr = self.model.sum(self.gamma_ik[i,k] for i in range(local_V))
                self.model.add(expr <= 1, name="Constrain10_{0}".format(k))

        # 约束11：每个time step，同一层的同一个block内，分配subblock数量不能超过3
        if 1 == 1:
            for t in range(params.T):
                if params.total_handle[t] >= 1:
                    for g in range(params.G):
                        expr = self.model.linear_expr()
                        for i in range(local_V):
                            vessel_idx = self.vessel_list[i]
                            # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
                            for k in params.block_set[g]:
                                expr.add_term(self.gamma_ik[i, k],params.l_it[vessel_idx][t])
                        self.model.add(expr <= 3, name="Constrain11_{0}_{1}".format(t, g))

        # 约束12：写法1--从每个subblock看，每个neighbor_set中，只能分配给一艘船
        if 1 == 1:
            for t in range(params.T):
                if params.total_handle[t] >= 1:
                    for n in range(params.K1):
                        for k in range(1, len(params.neighbor_set[n])):  # 不包括自己
                            midlist = [n]
                            midlist.append(params.neighbor_set[n][k])
                            expr = self.model.linear_expr()
                            index_neighbor = n
                            for i in range(local_V):
                                vessel_idx = self.vessel_list[i]
                                # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
                                for index in midlist:  # --形成一个pair 对 等价于 for k in neighbor_pair
                                    index_neighbor = index
                                    expr.add_term(self.gamma_ik[i, index],params.l_it[vessel_idx][t])
                            self.model.add(expr <= 1, name="Constrain12_{0}_({1}-{2})".format(t, n, index_neighbor))

        # 约束13：每个time step，异层转运的数量不能超过一个阈值
        if 1 == 1:
            for t in range(params.T):
                expr = self.model.linear_expr()
                for i in range(local_V):
                    vessel_idx = self.vessel_list[i]
                    # vessel_idx = self.temp_sequence.iloc[i]['vessel_idx']
                    if params.l_it[vessel_idx][t] == 1:
                        expr.add(1 / params.handle_i[vessel_idx]*(self.abs_ui1[i]+self.abs_li1[i]))
                self.model.add(expr <= params.C, name="Constrain13_{0}".format(t))
        # endregion
        time_end = time.time()


        time_111 = time.time()
        solution = self.model.solve(log_output=self.output_flag)
        time_222 = time.time()


        num_variables = self.model.number_of_variables
        num_constraints = self.model.number_of_constraints
        refiner = ConflictRefiner()  # 先实例化ConflictRefiner类
        res = refiner.refine_conflict(self.model)  # 将模型导入该类，调用方法
        res.display()
        print("第 {} 次迭代SWO_cplex_model 中变量数量={}   约束数量={}".format(iter_id+1,num_variables, num_constraints))
        if solution is not None:
            time_ssss = time.time()

            model_obj = solution.get_objective_value()
            self.swo_record.solving_time = round(time_end - time_start, 2)
            self.swo_record.obj = solution.get_objective_value()
            # 更新记录最优解的类对象
            for i in range(local_V):
                vessel_idx = self.vessel_list[i]
                for h in range(params.H):
                    self.swo_record.alpha_lih[vessel_idx, h] = solution.get_var_value(self.alpha_lih[i, h])
                    self.swo_record.alpha_uih[vessel_idx, h] = solution.get_var_value(self.alpha_uih[i, h])
                    self.swo_record.abs_li1[vessel_idx] = solution.get_var_value(self.abs_li1[i])
                    self.swo_record.abs_ui1[vessel_idx] = solution.get_var_value(self.abs_ui1[i])
                for k in range(params.K1):
                    if solution.get_var_value(self.gamma_ik[i,k]) > 0.5:
                        self.swo_record.beta_lik[vessel_idx, k] = solution.get_var_value(self.beta_lik[i, k])
                        self.swo_record.beta_uik[vessel_idx, k] = solution.get_var_value(self.beta_uik[i, k])
                        self.swo_record.gamma_ik[vessel_idx,k] = solution.get_var_value(self.gamma_ik[i,k])
                    else:
                        self.swo_record.beta_lik[vessel_idx, k] = 0
                        self.swo_record.beta_uik[vessel_idx, k] = 0
                        self.swo_record.gamma_ik[vessel_idx, k] = 0
            self.swo_record.cal_cost_i()

            print("doccplex 求解结果： obj = {0:.2f} s  转化为小时={1:.2f} h".format(model_obj, model_obj / 3600))
            print("每艘船预留堆场的最优解情况-------------")
            cost_i = [0 for _ in range(params.V + 1)]
            for i in range(local_V):
                vessel_idx = self.vessel_list[i]
                cost1 = params.time_p * (max(solution.get_var_value(self.alpha_lih[i, 0]), solution.get_var_value(self.alpha_lih[i, 1])) +
                                         max(solution.get_var_value(self.alpha_uih[i, 0]), solution.get_var_value(self.alpha_uih[i, 0])))
                cost2 = params.time_u * (solution.get_var_value(self.abs_ui1[i]) + solution.get_var_value(self.abs_li1[i]))
                cost3 = 0
                for k in range(params.K1):
                    cost3 += params.t_lki[k, vessel_idx] * solution.get_var_value(self.beta_lik[i, k]) + params.t_uki[k, vessel_idx] * solution.get_var_value(self.beta_uik[i, k])
                cost_i[vessel_idx] = cost1 + cost2 + cost3
            for i in range(local_V):
                vessel_idx = self.vessel_list[i]
                print("vessel-{:2}  cost = {:.2f}  abs_u={:.2f}  abs_l={:.2f} 预留subblock = ".
                      format(vessel_idx, cost_i[vessel_idx],solution.get_var_value(self.abs_ui1[i]),solution.get_var_value(self.abs_li1[i])), end=" ")
                for k in range(params.K1):
                    if solution.get_var_value(self.gamma_ik[i, k]) > 0.5:
                        print(f"{k:2} ", end="")
                print()
            time_eee = time.time()
            print("模型约束初始化耗时={:.2f}s".format(time_end - time_start))
            print("模型实际求解耗时  ={:.2f}s".format(time_222 - time_111))
            print("模型输出与赋值耗时={:.2f}s".format(time_eee-time_ssss))
        else:
            raise EOFError("第 {} 次迭代的 model_docplex 无解!".format(N))

class single_model:
    def __init__(self,vessel_index):
        self.solving_time = 0
        self.obj = params.max_bound
        self.vessel = vessel_index
        self.gamma_k = []

    def build_model(self):
        model = Cplex_model()
        maxbound = 999999
        minbound = -999999
        # region 定义决策变量
        alpha_uih = {}
        alpha_lih = {}
        beta_lik = {}
        beta_uik = {}
        ganma_ik = {}
        for h in range(params.H):
            name1 = "alpha_uij_{0}_".format(h)
            name2 = "alpha_lij_{0}_".format(h)
            alpha_uih[h] = model.integer_var(0, params.c_ui[self.vessel], name=name1)
            alpha_lih[h] = model.integer_var(0, params.c_li[self.vessel], name=name2)
        for k in range(params.K1):
            name3 = "beta_l{0}_{1}".format(self.vessel, k)
            name4 = "beta_u{0}_{1}".format(self.vessel, k)
            name5 = "ganma_{0}_{1}".format(self.vessel, k)
            beta_lik[k] = model.continuous_var(0, params.z, name=name3)
            beta_uik[k] = model.continuous_var(0, params.z, name=name4)
            ganma_ik[k] = model.binary_var(name=name5)
        # 辅助决策变量用于线性化
        name6 = "deta_u_{0}".format(self.vessel)
        name7 = "deta_l_{0}".format(self.vessel)
        name8 = "abs_u_{0}".format(self.vessel)
        name9 = "abs_l_{0}".format(self.vessel)
        name10 = "sum_u_{0}".format(self.vessel)
        name11 = "sum_i_{0}".format(self.vessel)
        deta_u_i = model.integer_var(0, maxbound, name=name6)
        deta_l_i = model.integer_var(0, maxbound, name=name7)
        abs_ui1 = model.integer_var(0, maxbound, name=name8)
        abs_li1 = model.integer_var(0, maxbound, name=name9)
        sum_ui1 = model.integer_var(minbound, maxbound, name=name10)
        sum_li1 = model.integer_var(minbound, maxbound, name=name11)
        # endregion

        # region 定义目标函数
        obj_expr = model.linear_expr()  # 创建一个空的线性表达式对象
        expr1 = model.linear_expr()
        expr1.add(params.time_p*(deta_l_i+deta_u_i)+params.time_u*(abs_ui1+abs_li1))
        expr2 = model.linear_expr()  # 创建一个空的线性表达式对象
        for k in range(params.K1):
            expr2.add_term(beta_uik[k], params.t_uki[k][self.vessel])
            expr2.add_term(beta_lik[k], params.t_lki[k][self.vessel])
        obj_expr.add(expr1)
        obj_expr.add(expr2)
        model.minimize(obj_expr)
        # endregion

        # region 定义约束条件
        # 目标函数中的等价替换
        for h in range(params.H):
            model.add(deta_l_i >= alpha_lih[h], name="linearing cons1_{0}_{1}".format(self.vessel,h))
            model.add(deta_u_i >= alpha_uih[h], name="linearing cons2_{0}_{1}".format(self.vessel, h))
        expr3 = model.sum(beta_lik[k] for k in range(params.K0))
        expr4 = model.sum(beta_uik[k] for k in range(params.K0))
        model.add(sum_li1 == alpha_lih[0] - expr3, name="Constrain_sum_l_{0}".format(self.vessel))
        model.add(sum_ui1 == alpha_uih[0] - expr4, name="Constrain_sum_u_{0}".format(self.vessel))
        model.add(abs_li1 == model.abs(sum_li1), name="abs_constrain_l_{0}".format(self.vessel))
        model.add(abs_ui1 == model.abs(sum_ui1), name="abs_constrain_u_{0}".format(self.vessel))

        # 约束2/4：每艘船的unloading量守恒、loading量守恒
        expr1 = model.sum(alpha_uih[h] for h in range(params.H))
        expr2 = model.sum(alpha_lih[h] for h in range(params.H))
        model.add(expr1 == params.c_ui[self.vessel], name="Constrain2_u")
        model.add(expr2 == params.c_li[self.vessel], name="Constrain4_l")
        # 约束 3/5：每艘船unloading/loading到堆场的数量守恒
        expr3 = model.sum(beta_uik[k] for k in range(params.K1))
        expr4 = model.sum(beta_lik[k] for k in range(params.K1))
        model.add(expr3 == params.c_ui[self.vessel], name="Constrain2_u")
        model.add(expr4 == params.c_li[self.vessel], name="Constrain4_l")

        # 约束6：unloading 和 loading 在每一层的上界
        for k in range(params.K1):
            model.add(beta_lik[k] + beta_uik[k] <= params.z*ganma_ik[k], name="Constrain6_{0}".format(k))
        # 约束9：每层的subblock需要小于对应的params.r_ih
        expr1 = model.sum(ganma_ik[k] for k in range(params.K0))
        expr2 = model.sum(ganma_ik[k] for k in range(params.K0, params.K1))
        model.add(expr1 <= params.r_ih[self.vessel][0], name="Constrain9_0_{0}".format(self.vessel))
        model.add(expr2 <= params.r_ih[self.vessel][1], name="Constrain9_1_{0}".format(self.vessel))

        # 约束11：每个time step，同一层的同一个block内，分配subblock数量不能超过3
        for t in range(params.T):
            if params.total_handle[t] >= 1:
                for g in range(params.G):
                    expr = model.sum(params.l_it[self.vessel][t] * ganma_ik[k] for k in params.block_set[g])
                    model.add(expr <= 3, name="Constrain11_{0}_{1}".format(t, g))

        # 约束11：每个time step，同一个neighbor内，分配subblock数量不能超过1
        for t in range(params.T):
            if params.total_handle[t] >= 1:
                for n in range(params.K1):
                    for k in range(1, len(params.neighbor_set[n])):  # 不包括自己
                        midlist = [n]
                        midlist.append(params.neighbor_set[n][k])
                        expr = model.linear_expr()
                        index_neighbor = n
                        for index in midlist:  # --形成一个pair 对 等价于 for k in neighbor_pair
                            index_neighbor = index
                            expr.add_term(ganma_ik[index], params.l_it[self.vessel][t])
                        model.add(expr <= 1, name="Constrain12_{0}_({1}-{2})".format(t, n, index_neighbor))
        time_start = time.time()
        solution = model.solve(log_output=False)
        time_end = time.time()
        num_variables = model.number_of_variables
        num_constraints = model.number_of_constraints
        refiner = ConflictRefiner()  # 先实例化ConflictRefiner类
        res = refiner.refine_conflict(model)  # 将模型导入该类，调用方法
        res.display()
        print("single_model_{} 中决策变量个数={}  约束数量={}".format(self.vessel,num_variables, num_constraints))
        if solution is not None:
            model_obj = solution.get_objective_value()
            self.solving_time = round(time_end - time_start, 2)
            self.obj = solution.get_objective_value()
            print("single_model_{0} 求解结果： obj = {1:.2f} s  转化为小时={2:.2f} h".format(self.vessel,model_obj, model_obj / 3600))
            print("vessel-{}  cost = {:.2f} abs_u={}  abs_i = {}  预留subblock = ".
                  format(self.vessel,model_obj,solution.get_var_value(abs_ui1),solution.get_var_value(abs_li1)),end=" ")
            for k in range(params.K1):
                if solution.get_var_value(ganma_ik[k]) > 0.5:
                    self.gamma_k.append(k)
                    print(f"{k:2} ", end="")
            print()
        else:
            print("docplex 无解!")
    # endregion
